﻿using System;
using System.Collections;
using UnityEngine;





public interface IMonsterTask
{
    //执行该任务的怪兽
    Monster monster { get; set; }

    //额外的中断任务的条件，某些情况下，不需要完全完成任务就可以中断该任务(例如，向左移动100 个单位，但是中途遇到玩家，理应提前中断该任务)
    Func<bool> extraBreakTaskCondition { get; set; }   
       
    /// <summary>
    /// 执行任务;返回值表示是否执行完任务
    /// </summary>
    bool ExecuteTask();
}



public struct MonsterTaskIdle : IMonsterTask
{
    public Monster monster { get; set; }
    public Func<bool> extraBreakTaskCondition { get; set; }
    public float idleTime;

    public MonsterTaskIdle(Monster monster, Func<bool> extraBreakTaskCondition, float idleTime)
    {
        this.monster = monster;
        this.extraBreakTaskCondition = extraBreakTaskCondition;
        this.idleTime = idleTime;

        if(this.extraBreakTaskCondition == null)
        {
            this.extraBreakTaskCondition = () => { return false; };
        }
    }

    public bool ExecuteTask()
    {
        if (monster.animController.IsCurrAnimName(MonsterAnimName.Hit) || extraBreakTaskCondition())
        {
            return true;
        }
        else if (monster.animController.IsMovingState())
        {
            monster.animController.Play(MonsterAnimName.Idle);
        }

      
        if (monster.animController.IsCurrAnimName(MonsterAnimName.Idle))
        {
            idleTime -= Time.deltaTime;
            if (idleTime <= 0.0f)
            {
                return true;
            }
        }
      
        return false;
    }
}



public struct MonsterTaskHorizontalWalk : IMonsterTask
{
    public Monster monster { get; set; }
    public Func<bool> extraBreakTaskCondition { get; set; }
    public Vector3 horizontal;
    public float walkDistance;
    private float originX;

    public MonsterTaskHorizontalWalk(Monster monster, Func<bool> extraBreakTaskCondition, Vector3 horizontal, float walkDistance)
    {
        this.monster = monster;
        this.extraBreakTaskCondition = extraBreakTaskCondition;
        this.horizontal = horizontal;
        this.walkDistance = walkDistance;
        originX = monster.transform.position.x;

        if (this.extraBreakTaskCondition == null)
        {
            this.extraBreakTaskCondition = () => { return false; };
        }
    }

    public bool ExecuteTask()
    {
        if (!monster.animController.IsAttackState())
        {
            if (monster.animController.IsCurrAnimName(MonsterAnimName.Hit) || extraBreakTaskCondition())
            {
                return true;
            }
            else if(monster.IsGround && (monster.animController.IsCurrAnimName(MonsterAnimName.Idle) || monster.animController.IsCurrAnimName(MonsterAnimName.Run)))
            {
                monster.animController.Play(MonsterAnimName.Walk);
            }
       
            if (monster.animController.IsCurrAnimName(MonsterAnimName.Walk))
            {
                monster.HorizontalMoveWalk(horizontal);
                if (Mathf.Abs(monster.transform.position.x - originX) >= walkDistance)
                {
                    monster.animController.Play(MonsterAnimName.Idle);
                    return true;
                }
            } 
        }
        return false;
    }
}



public struct MonsterTaskHorizontalRun : IMonsterTask
{
    public Monster monster { get; set; }
    public Func<bool> extraBreakTaskCondition { get; set; }
    public Vector3 horizontal;
    public float runDistance;
    private float originX;

    public MonsterTaskHorizontalRun(Monster monster, Func<bool> extraBreakTaskCondition, Vector3 horizontal, float runDistance)
    {
        this.monster = monster;
        this.extraBreakTaskCondition = extraBreakTaskCondition;
        this.horizontal = horizontal;
        this.runDistance = runDistance;
        originX = monster.transform.position.x;

        if (this.extraBreakTaskCondition == null)
        {
            this.extraBreakTaskCondition = () => { return false; };
        }
    }

    public bool ExecuteTask()
    {
        if (!monster.animController.IsAttackState())
        {
            if (monster.animController.IsCurrAnimName(MonsterAnimName.Hit) || extraBreakTaskCondition())
            {
                return true;
            }
            else if (monster.IsGround && (monster.animController.IsCurrAnimName(MonsterAnimName.Idle) || monster.animController.IsCurrAnimName(MonsterAnimName.Walk)))
            {
                monster.animController.Play(MonsterAnimName.Run);
            }
          
            if (monster.animController.IsCurrAnimName(MonsterAnimName.Run) || monster.animController.IsCurrAnimName(MonsterAnimName.Jump))
            {
                monster.HorizontalMoveRun(horizontal);
                if (Mathf.Abs(monster.transform.position.x - originX) >= runDistance)
                {
                    monster.animController.Play(MonsterAnimName.Idle);
                    return true;
                }
            }
        }
        return false;
    }
}



public struct MonsterTaskVerticalMove : IMonsterTask
{
    public Monster monster { get; set; }
    public Func<bool> extraBreakTaskCondition { get; set; }
    public Vector3 vertical;
    public float high;
    private float originY;

    public MonsterTaskVerticalMove(Monster monster, Vector3 vertical, float high)
    {
        this.monster = monster;
        this.extraBreakTaskCondition = null;
        this.vertical = vertical;
        this.high = high;
        originY = monster.transform.position.y;
    }

    public bool ExecuteTask()
    {
        if (!monster.animController.IsAttackState() && !monster.animController.IsCurrAnimName(MonsterAnimName.Hit))
        {
            if (!monster.animController.IsCurrAnimName(MonsterAnimName.Jump))
            {
                monster.animController.Play(MonsterAnimName.Jump);
            }
            else if (monster.jumpCount > 0)
            {
                --monster.jumpCount;
                monster.StopCoroutine(VerticalMove());
                monster.StartCoroutine(VerticalMove());
            }
            return true;
        }
        return false;   
    }

    private IEnumerator VerticalMove()
    {
        float verticalMoveSpeed = 16.0f;
        while (Mathf.Abs(monster.transform.position.y - originY) < high && !monster.animController.IsCurrAnimName(MonsterAnimName.Hit))
        {
            monster.transform.Translate(vertical * verticalMoveSpeed * Time.deltaTime, Space.World);
            yield return null;
        }

        monster.StopCoroutine(OnGround());
        monster.StartCoroutine(OnGround());
    }

    private IEnumerator OnGround()
    {
        while(!monster.IsGround)
        {
            yield return null;
        }

        if (monster.animController.IsCurrAnimName(MonsterAnimName.Jump))
        {
            monster.animController.Play(MonsterAnimName.Idle);
        }

        monster.jumpCount = monster.jumpCountLimit;
    }
}




public struct MonsterTaskHit : IMonsterTask
{
    public Monster monster { get; set; }
    public Func<bool> extraBreakTaskCondition { get; set; }
    public float stiffTime;             //僵硬时间
    public DamageInfo damageInfo;
    public GameObject attacker;
    public bool breakAction;
    private bool marked;

    public MonsterTaskHit(Monster monster, Func<bool> extraBreakTaskCondition, float stiffTime, DamageInfo damageInfo, GameObject attacker, bool breakAction)
    {
        this.monster = monster;
        this.extraBreakTaskCondition = extraBreakTaskCondition;
        this.stiffTime = stiffTime;
        this.damageInfo = damageInfo;
        this.attacker = attacker;
        this.breakAction = breakAction;
        marked = false;

        if (this.extraBreakTaskCondition == null)
        {
            this.extraBreakTaskCondition = () => { return false; };
        }
    }

    public bool ExecuteTask()
    {
        if (!marked)
        {
            if (!monster.animController.IsCurrAnimName(MonsterAnimName.Hit) && (breakAction || damageInfo.type == DamageType.Normal))
            {
                monster.animController.Play(MonsterAnimName.Hit);
                monster.Hit(damageInfo, attacker);
                marked = true;
            }
            else
            {
                monster.Hit(damageInfo, attacker);
                marked = true;
                return true;
            }
        }

        //Animator.Play 后也不是马上能到达指定动画状态，也是纳闷
        if (monster.animController.IsCurrAnimName(MonsterAnimName.Hit))
        {
            stiffTime -= Time.deltaTime;
            if(stiffTime <= 0)
            {
                if ((monster.animController.HasParameterOfType(MonsterAnimName.Fall, AnimatorControllerParameterType.Trigger)
                    && monster.seriesTakeDamageCount >= 5) && (breakAction || damageInfo.type == DamageType.Normal))
                {
                    monster.animController.Play(MonsterAnimName.Fall);
                }
                else
                {
                    monster.animController.Play(MonsterAnimName.Idle);
                    return true;
                }
             
            }  
        }
        else if(monster.animController.IsCurrAnimName(MonsterAnimName.Fall) && monster.animController.GetCurrAnimNormalizedTime() >= 1.0f)
        {
            monster.animController.Play(MonsterAnimName.Idle);
            return true;
        }
      
        return false;
    }
}



public struct MonsterTaskNormalAttack : IMonsterTask
{
    public Monster monster { get; set; }
    public Func<bool> extraBreakTaskCondition { get; set; }

    public MonsterTaskNormalAttack(Monster monster, Func<bool> extraBreakTaskCondition)
    {
        this.monster = monster;
        this.extraBreakTaskCondition = extraBreakTaskCondition;
        if (this.extraBreakTaskCondition == null)
        {
            this.extraBreakTaskCondition = () => { return false; };
        }
    }

    public bool ExecuteTask()
    {
        if (!monster.animController.IsAttackState() || monster.animController.IsCurrAnimName(MonsterAnimName.NormalAttack))
        {
            if (monster.animController.IsCurrAnimName(MonsterAnimName.Hit) || extraBreakTaskCondition())
            {
                return true;
            }

            //这个算是留一个怪兽的弱点吧
            if (monster.IsInNormalAttackCD())
            {
                monster.animController.Play(MonsterAnimName.Idle);
            }
            else if (!monster.animController.IsCurrAnimName(MonsterAnimName.NormalAttack))
            {
                monster.animController.Play(MonsterAnimName.NormalAttack); 
            }
             
            if(monster.animController.IsCurrAnimName(MonsterAnimName.NormalAttack) && monster.animController.GetCurrAnimNormalizedTime() >= 1.0f)
            {
                monster.StartAttackCDTiming();
                monster.animController.Play(MonsterAnimName.Idle);
                return true;
            }
        }
        return false;
    }
}